#ifndef PW_PBL_COROUTINE_RUSTMIMIC_HPP
#define PW_PBL_COROUTINE_RUSTMIMIC_HPP

#include <cstddef>
#include <functional>
#include <optional>
#include <string_view>
#include <type_traits>
#include <utility>
#include <memory>
#include <expected>
#include "Self.hpp"
#include "Throw.hpp"
#include "defer.hpp"
#include "Concepts/Core.hpp"

namespace pw_pbl
{
	/// wrap type T but remove destructor, user should call destruct manually
	template <typename T> requires(!std::is_reference_v<T>)
	union ManualDestruct
	{
	private:
		T obj;

	public:
		template <typename... P>
		constexpr ManualDestruct(P &&...p) : obj{std::forward<P>(p)...} {}
		constexpr ~ManualDestruct() noexcept {}

		constexpr void destruct() { std::destroy_at(&obj); }

		template <typename Self>
		constexpr ttForwardApply<Self &&, T> get(this Self &&self) { return forward_cast<Self, ManualDestruct>(self).obj; }
	};

	/// wrap type T but remove destructor and maybe not construct when defined, user should call destruct manually (and construct if not construct when defined)
	template <typename T> requires(!std::is_reference_v<T>)
	union MaybeUninit
	{
	private:
		T obj;
		[[no_unique_address]] std::tuple<> none;

	public:
		template <typename... P> requires(sizeof...(P) != 0)
		constexpr MaybeUninit(P &&...p) : obj{std::forward<P>(p)...} {}
		constexpr MaybeUninit() : none{} {}
		constexpr ~MaybeUninit() noexcept {}
		MaybeUninit(const MaybeUninit &) = delete;
		MaybeUninit(MaybeUninit &&) = delete;

		template <typename... P>
		constexpr void construct(P &&...p) { std::construct_at(&obj, std::forward<P>(p)...); }
		constexpr void destruct() { std::destroy_at(&obj); }

		template <typename Self>
		constexpr ttForwardApply<Self &&, T> get(this Self &&self) { return forward_cast<Self, MaybeUninit>(self).obj; }

		/// move data out and destruct old, user must ensure data has been constructed
		constexpr ttPatchArray<T> take()
		{
			defer destroy([this] { this->destruct(); });
			return std::move(this->get());
		}
	};

	/// 可选值封装
	/// @note Option<std::type_identity<T>>为公共接口，为Option<T>的基类，特化Option<T>时通常应以此做为基类且应实现is_none和get_unchecked
	/// @note Option<T>或其特化为具体实现类，必须定义is_none和get_unchecked，且继承Option<std::type_identity<T>>
	template <typename T>
	class Option;

	/// 可选值封装公共接口
	/// @note 为Option<T>的基类，特化Option<T>时通常应以此做为基类且应实现is_none和get_unchecked
	template <typename T>
	class Option<std::type_identity<T>>
	{
	protected:
		constexpr Option() = default;

	public:
		constexpr bool is_some(this const Option<T> &self) { return !self.is_none(); }
		constexpr void set(this auto &&self, T v) { std::destroy_at(&self), std::construct_at(&self, std::forward<T>(v)); }
		constexpr void reset(this auto &&self) { std::destroy_at(&self), std::construct_at(&self); }
		constexpr T unwrap_unchecked(this auto &&self)
		{
			T result = std::forward<T>(self.get_unchecked());
			self.reset();
			return result;
		}

		template <typename O>
		constexpr T unwrap_or(this O &&self, T fallback) { return self.is_none() ? std::forward<T>(fallback) : std::forward<O>(self).unwrap_unchecked(); }
	};

	template <typename T>
	class Option : public Option<std::type_identity<T>>
	{
		std::optional<T> raw;

	public:
		constexpr Option() = default;
		constexpr Option(T data) : raw(std::forward<T>(data)) {}
		constexpr bool is_none() const { return !raw.has_value(); }
		constexpr auto &get_unchecked() & { return *raw; }
		constexpr auto &get_unchecked() const & { return *raw; }
		constexpr auto &&get_unchecked() && { return *std::move(raw); }
	};

	template <typename T>
	class Option<T &> : public Option<std::type_identity<T &>>
	{
		T *raw;

	public:
		constexpr Option() : raw(nullptr) {}
		constexpr Option(std::reference_wrapper<T> data) : raw(&data.get()) {}
		constexpr Option(T &data) requires(!std::is_function_v<T>) : raw(&data) {}
		constexpr Option(T *data) : raw(data) {}
		constexpr bool is_none() const { return raw == nullptr; }
		constexpr T &get_unchecked() const { return *raw; }
	};

	template <typename T>
	class Option<std::reference_wrapper<T>> : public Option<std::type_identity<std::reference_wrapper<T>>>
	{
		T *raw;

	public:
		constexpr Option() : raw(nullptr) {}
		constexpr Option(std::reference_wrapper<T> data) : raw(&data.get()) {}
		constexpr Option(T &data) : raw(&data) {}
		constexpr Option(T *data) : raw(data) {}
		constexpr bool is_none() const { return raw == nullptr; }
		constexpr std::reference_wrapper<T> get_unchecked() const { return {*raw}; }
	};

	template <typename T>
	class Option<T *>
	{
		static_assert(!std::is_pointer_v<T *>, "maybe you just want Option<T&>");
	};

	template <>
	class Option<std::string_view> : public Option<std::type_identity<std::string_view>>
	{
		std::string_view raw;

	public:
		constexpr Option() = default;
		constexpr Option(std::string_view data) : raw(data) {}
		constexpr bool is_none() const { return raw.data() == nullptr; }
		constexpr std::string_view &get_unchecked() & { return raw; }
		constexpr const std::string_view &get_unchecked() const & { return raw; }
		constexpr std::string_view &&get_unchecked() && { return std::move(raw); }
	};

	template <typename T>
	constexpr Option<T> Some(T &&data) { return {std::forward<T>(data)}; }

	template <typename T>
	constexpr Option<T> Some(Option<T> &&data) { return std::move(data); }

	template <typename T>
	constexpr Option<T> Some(const Option<T> &data) { return data; }

	template <typename T>
	constexpr Option<T &> Some(std::reference_wrapper<T> data) { return {data}; }

	/// 空值类型，通常作为Option<T>的空值或支持Option<T>优化的类型T的空值
	constexpr struct None_t
	{
		template <typename T>
		constexpr operator Option<T>() const { return {}; }
	} None; //< 空值，通常作为Option<T>的空值或支持Option<T>优化的类型T的空值

	/// 任意可以从None构造且可以比较是否为None的类型T均可优化Option<T>类型，Option<T>与T有相同的内存布局
	template <std::constructible_from<None_t> T> requires std::equality_comparable_with<T, None_t>
	class Option<T> : public Option<std::type_identity_t<T>>
	{
		T raw;

	public:
		constexpr Option() : raw{None} {}
		constexpr Option(T raw) : raw(std::forward<T>(raw)) {}
		constexpr bool is_none() const { return raw == None; }
		template <typename Self>
		constexpr ttForwardApply<Self &&, T> get_unchecked(this Self &&self) { return std::forward_like<Self>(self.raw); }
	};

	template <std::invocable<> F>
	class defer<Option<F>>
	{
		Option<F> obj;

	public:
		constexpr defer(Option<F> f) : obj{std::move(f)} {}
		constexpr ~defer()
		{
			if (obj.is_some())
				std::move(obj).unwrap_unchecked()();
		}
		defer(const defer &) = delete;
		defer(defer &&oth) : obj{oth.obj.is_some() ? Option<F>(oth.obj.unwrap_unchecked()) : None} {}
	};

	/// 非0整型
	template <std::integral T>
	struct NonZero
	{
		T raw;

	private:
		constexpr NonZero(T v) noexcept : raw(v) {}
		friend Option<NonZero>;

	public:
		static constexpr Option<NonZero> try_make(T v) { return {NonZero(v)}; }
		static constexpr NonZero new_unchecked(T v) { pw_pbl_assert(v != 0) return NonZero(v); }
	};

	template <std::integral T>
	class Option<NonZero<T>> : public Option<std::type_identity<NonZero<T>>>
	{
		NonZero<T> raw;

	public:
		constexpr Option() noexcept : raw(0) {}
		constexpr Option(NonZero<T> v) noexcept : raw(v.raw) {}
		constexpr bool is_none() const { return this->raw.raw == 0; }
		constexpr auto get_unchecked() const { return this->raw; }

		constexpr Option(T v) noexcept : raw(v) {}
		constexpr operator T() const { return raw.raw; }
	};

	namespace _rust
	{
		template <typename...>
		struct OptionWrapType;

		template <typename T>
		struct OptionWrapType<Option<T>>
		{
			using type = T;
		};
	} // namespace _rust

	template <typename T>
	using OptionWrapType = _rust::OptionWrapType<T>::type;

	template <typename T>
	concept ccOption = requires { typename OptionWrapType<T>; };

	namespace _rust
	{
		/// 参数可以是void的调用结果
		template <typename F, typename P>
		struct va_invoke_result : public std::invoke_result<F, P>
		{};

		template <typename F>
		struct va_invoke_result<F, void> : public std::invoke_result<F>
		{};

		template <typename F, typename P>
		using va_invoke_result_t = typename va_invoke_result<F, P>::type;

		template <typename OK, typename ERR>
		class Result;
	} // namespace _rust

	template <typename OK, typename ERR>
	class Result;

	template <typename OK, typename ERR>
	class _rust::Result
	{
		template <typename Self>
		using ok_type_of = ttForwardApply<Self &&, OK>;

		template <typename Self>
		using err_type_of = ttForwardApply<Self &&, ERR>;

		using unvoid_ok = std::conditional_t<std::is_void_v<OK>, std::tuple<>, OK>;

		using unvoid_err = std::conditional_t<std::is_void_v<ERR>, std::tuple<>, ERR>;

	public:
		explicit constexpr operator bool(this const auto &self) { return self.is_ok(); }

		constexpr bool is_err(this const auto &self) { return !self.is_ok(); }

		template <typename Self, typename F>
		constexpr bool is_ok_and(this Self &&self, F &&f) requires std::convertible_to<va_invoke_result_t<F, ok_type_of<Self>>, bool>
		{
			if constexpr (std::is_void_v<OK>)
				return self.is_ok() && std::forward<F>(f)();
			else
				return self.is_ok() && std::forward<F>(f)(std::forward<Self>(self).get_ok_unchecked());
		}

		template <typename Self, typename F>
		constexpr bool is_err_and(this Self &&self, F &&f) requires std::convertible_to<va_invoke_result_t<F, err_type_of<Self>>, bool>
		{
			if constexpr (std::is_void_v<ERR>)
				return self.is_err() && std::forward<F>(f)();
			else
				return self.is_err() && std::forward<F>(f)(std::forward<Self>(self).get_err_unchecked());
		}

		template <typename Self, typename F>
		constexpr auto map_ok(this Self &&self, F &&f) -> pw_pbl::Result<va_invoke_result_t<F, ok_type_of<Self>>, ERR>
		{
			using mapped_ok = va_invoke_result_t<F, ok_type_of<Self>>;
			using TResult = pw_pbl::Result<mapped_ok, ERR>;
			if (self.is_ok())
				if constexpr (std::is_void_v<mapped_ok>)
					return TResult::Ok();
				else if constexpr (std::is_void_v<OK>)
					return TResult::Ok(std::forward<F>(f)());
				else
					return TResult::Ok(std::forward<F>(f)(std::forward<Self>(self).get_ok_unchecked()));
			else if constexpr (std::is_void_v<ERR>)
				return TResult::Err();
			else
				return TResult::Err(std::forward<Self>(self).get_err_unchecked());
		}
		template <typename Self, typename F>
		constexpr auto map(this Self &&self, F &&f) -> pw_pbl::Result<va_invoke_result_t<F, ok_type_of<Self>>, ERR> { return std::forward<Self>(self).map_ok(std::forward<F>(f)); }

		template <typename Self, typename F>
		constexpr auto map_err(this Self &&self, F &&f) -> pw_pbl::Result<OK, va_invoke_result_t<F, err_type_of<Self>>>
		{
			using mapped_err = va_invoke_result_t<F, err_type_of<Self>>;
			using TResult = pw_pbl::Result<OK, mapped_err>;
			if (self.is_err())
				if constexpr (std::is_void_v<mapped_err>)
					return TResult::Err();
				else if constexpr (std::is_void_v<ERR>)
					return TResult::Err(std::forward<F>(f)());
				else
					return TResult::Err(std::forward<F>(f)(std::forward<Self>(self).get_err_unchecked()));
			else if constexpr (std::is_void_v<OK>)
				return TResult::OK();
			else
				return TResult::OK(std::forward<Self>(self).get_ok_unchecked());
		}

		template <typename Self>
		constexpr OK unwrap_or(this Self &&self, unvoid_ok v) requires(!std::is_void_v<OK>) { return std::forward<Self>(self).unwrap_ok_or(std::forward<OK>(v)); }

		template <typename Self>
		constexpr OK unwrap_ok_or(this Self &&self, unvoid_ok v) requires(!std::is_void_v<OK>) { return self.is_ok() ? std::move(self).get_ok_unchecked() : std::forward<OK>(v); }

		template <typename Self>
		constexpr ERR unwrap_err_or(this Self &&self, unvoid_err v) requires(!std::is_void_v<ERR>) { return self.is_err() ? std::move(self).get_err_unchecked() : std::forward<ERR>(v); }
	};

	template <typename OK, typename ERR>
	class Result : public _rust::Result<OK, ERR>
	{
		std::expected<OK, ERR> data;

		constexpr Result(std::expected<OK, ERR> &&d) : data(std::move(d)) {}

	public:
		constexpr Result() requires std::is_default_constructible_v<ERR> : Result{std::unexpected<ERR>{}} {}
		constexpr bool is_ok() const { return data.has_value(); }
		constexpr decltype(auto) get_ok_unchecked(this auto &&self) { return *std::forward_like<decltype(self)>(self.data); }
		constexpr decltype(auto) get_err_unchecked(this auto &&self) { return std::forward_like<decltype(self)>(self.data).error(); }

		static constexpr Result Ok(auto &&v) { return {OK(std::forward<decltype(v)>(v))}; }
		static constexpr Result Err(auto &&v) { return {std::unexpected(ERR(std::forward<decltype(v)>(v)))}; }
	};

	template <>
	class Result<void, void> : public _rust::Result<void, void>
	{
		bool _ok;

		constexpr Result(bool v) : _ok(v) {}

	public:
		constexpr Result() = default;
		constexpr bool is_ok() const { return _ok; }
		constexpr void get_ok_unchecked() const {}
		constexpr void get_err_unchecked() const {}

		static constexpr Result Ok() { return {true}; }
		static constexpr Result Err() { return {false}; }
	};

	template <typename ERR>
	class Result<void, ERR> : public _rust::Result<void, ERR>
	{
		Option<ERR> _err;

		constexpr Result(Option<ERR> v) : _err(std::move(v)) {}

	public:
		constexpr Result() = default;
		constexpr bool is_ok() const { return _err.is_none(); }
		constexpr bool is_err() const { return _err.is_some(); }
		constexpr void get_ok_unchecked() const {}
		constexpr decltype(auto) get_err_unchecked(this auto &&self) { return std::forward_like<decltype(self)>(self._err).get_unchecked(); }

		static constexpr Result Ok() { return {}; }
		static constexpr Result Err(auto &&v) { return {Some(ERR(std::forward<decltype(v)>(v)))}; }
	};

	template <typename OK>
	class Result<OK, void> : public _rust::Result<OK, void>
	{
		Option<OK> _ok;

		constexpr Result(Option<OK> v) : _ok(std::move(v)) {}

	public:
		constexpr Result() = default;
		constexpr bool is_ok() const { return _ok.is_some(); }
		constexpr bool is_err() const { return _ok.is_none(); }
		constexpr decltype(auto) get_ok_unchecked(this auto &&self) { return std::forward_like<decltype(self)>(self._ok).get_unchecked(); }
		constexpr void get_err_unchecked() const {}

		static constexpr Result Ok(auto &&v) { return {Some(OK(std::forward<decltype(v)>(v)))}; }
		static constexpr Result Err() { return {}; }
	};

	template <typename T>
	struct Ok
	{
		T _v;
		constexpr Ok(T &&v) : _v(std::forward<T>(v)) {}

		template <typename Self, typename ERR>
		constexpr operator Result<T, ERR>(this Self &&self) { return Result<T, ERR>::Ok(std::forward<ttForwardApply<Self, T>>(self._v)); }

		template <typename Self, typename NOK, typename ERR> requires std::convertible_to<ttForwardApply<Self, T> &&, NOK>
		constexpr operator Result<NOK, ERR>(this Self &&self) { return Result<NOK, ERR>::Ok(std::forward<ttForwardApply<Self, T>>(self._v)); }
	};

	template <>
	struct Ok<void>
	{
		constexpr Ok() = default;

		template <typename ERR>
		constexpr operator Result<void, ERR>() const { return Result<void, ERR>::Ok(); }

		template <typename OK, typename ERR> requires std::is_default_constructible_v<OK>
		constexpr operator Result<OK, ERR>() const { return Result<OK, ERR>::Ok({}); }
	};

	Ok() -> Ok<void>;

	template <typename T>
	Ok(T &) -> Ok<T &>;

	template <typename T>
	struct Err
	{
		T _v;
		constexpr Err(T &&v) : _v(std::forward<T>(v)) {}

		template <typename Self, typename OK>
		constexpr operator Result<OK, T>(this Self &&self) { return Result<OK, T>::Err(std::forward<ttForwardApply<Self, T>>(self._v)); }

		template <typename Self, typename OK, typename NERR> requires std::convertible_to<ttForwardApply<Self, T> &&, NERR>
		constexpr operator Result<OK, NERR>(this Self &&self) { return Result<OK, NERR>::Err(std::forward<ttForwardApply<Self, T>>(self._v)); }
	};

	template <>
	struct Err<void>
	{
		constexpr Err() = default;

		template <typename OK>
		constexpr operator Result<OK, void>() const { return Result<OK, void>::Err(); }

		template <typename OK, typename ERR> requires std::is_default_constructible_v<ERR>
		constexpr operator Result<OK, ERR>() const { return Result<OK, ERR>::Err({}); }
	};

	Err() -> Err<void>;

	template <typename T>
	Err(T &) -> Err<T &>;

} // namespace pw_pbl

#endif // PW_PBL_COROUTINE_RUSTMIMIC_HPP
